package com.itheima.d3_annotation;

import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 目标：掌握注解的解析。
 * 注解的操作中经常需要进行解析，注解的解析就是判断是否存在注解，存在注解就解析出内容。
 *
 * 什么是注解的解析?
 * 就是判断类上、方法上、成员变量上是否存在注解，并把注解里的内容给解析出来。
 * 如何解析注解?
 * 指导思想:要解析谁上面的注解，就应该先拿到谁，
 * 比如要解析类上面的注解，则应该先获取该类的Class对象，再通过Class对象解析其上面的注解。
 * 比如要解析成员方法上的注解，则应该获取到该成员方法的Method对象，再通过Method对象解析其上面的注解
 * Class对象、Method对象、Field对象,Constructor对象、都实现了AnnotatedElement接口，它们都拥有解析注解的能力。
 *
 * 与注解解析相关的接口
 * Annotation: 注解的顶级接口，注解都是Annotation类型的对象
 * AnnotatedElement接口:该接口提供了解析注解的方法
 *      方法
 *public Annotation[] getDeclaredAnnotations()                           获得当前对象上使用的所有注解，返回注解数组。
 *public T getDeclaredAnnotation(Class<T> annotationClass)               根据注解类型获得对应注解对象
 *public boolean isAnnotationPresent(Class<Annotation> annotationClass)  判断当前对象是否使用了指定的注解，如果使用了则返回true，否则false
 *
 *  这个案例和ppt上面写的也是不一样
 * 解析注解的案例，具体需求如下:
 *  1.定义注解MyTest4，要求如
 * 包含属性:String value()
 * 包含属性:double aaa()，默认值为 100
 * 包含属性:string[] bbb()
 * 限制注解使用的位置:类和成员方法上
 * 指定注解的有效范围:一直到运行时
 * 2.定义一个类叫:Demo，在类中定义一个test1方法，并在该类和其方法上使用MyTest4注解
 * 3.定义AnnotationTest3测试类，解析Demo类中的全部注解。
 *
 */
public class AnnotationTest3 {
    @Test
    public void parseClass(){
        // 1、先得到Class对象
        //自己可以看Class的源码，实现了AnnotatedElement接口
        Class c = Demo.class;
        // 2、解析Demo类上的注解
        //isAnnotationPresent方法： 判断当前对象是否使用了指定的注解，如果使用了则返回true，否则false
        if(c.isAnnotationPresent(MyTest4.class)){
            //多态写法：因为所有的注解对象都是Annotation的实现类对象
            //Annotation myTest4 = c.getDeclaredAnnotation(MyTest4.class);

            //强转一下：     getDeclaredAnnotation方法： 根据注解类型获得对应注解对象
            MyTest4 myTest4 =
                    (MyTest4) c.getDeclaredAnnotation(MyTest4.class);
            System.out.println(myTest4.value());
            System.out.println(myTest4.aaa());
            System.out.println(Arrays.toString(myTest4.bbb()));
        }
    }

    @Test
    public void parseMethod() throws Exception {
        // 1、先得到Class对象
        Class c = Demo.class;
        //再得到Method方法对象   Method方法对象可以自己看源码，一直看，发现也是继承了AnnotatedElement接口
        Method m = c.getDeclaredMethod("test1");        //有异常直接抛出
        // 2、解析Demo类中方法上的注解
        //isAnnotationPresent方法： 判断当前对象是否使用了指定的注解，如果使用了则返回true，否则false
        if(m.isAnnotationPresent(MyTest4.class)){
            //getDeclaredAnnotation方法： 根据注解类型获得对应注解对象
            MyTest4 myTest4 =
                    (MyTest4) m.getDeclaredAnnotation(MyTest4.class);
            System.out.println(myTest4.value());
            System.out.println(myTest4.aaa());
            System.out.println(Arrays.toString(myTest4.bbb()));
        }
    }
}
